package com.smart.tool.core;

import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

/**
 * @Author gao.gwq
 * @Version CollectionUtils.java, v 0.1 2024年06月14日 14:54 gao.gwq
 * @Description: TODO 集合通用处理类
 */
public class CollectionTool {
    /**
     * 数组转字符串，按照指定的分隔符进行分割
     * example:
     * List<String> list = Lists.newArrayList("1","2","3","4","5","6","7","8","9","10");
     * String join = join(list, ",");
     * System.out.println(join);//1,2,3,4,5,6,7,8,9,10
     *
     * @param col      col
     * @param splitter splitter
     * @return join result
     */
    public static String join(Collection<?> col, String splitter) {

        if (StringUtils.isEmpty(splitter)) {
            throw new IllegalArgumentException("splitter is null");
        }

        if (org.apache.commons.collections4.CollectionUtils.isEmpty(col)) {
            return StringUtils.EMPTY;
        }

        StringJoiner joiner = new StringJoiner(splitter);
        for (Object o : col) {
            joiner.add(String.valueOf(o));
        }
        return joiner.toString();
    }

    /**
     * 判断参数是否存在于当前集合
     *
     * @param list example
     *             List<Integer> list = new ArrayList<Integer>(){{
     *             add(1);
     *             add(2);
     *             }};
     *             boolean exist =  listContainObj(list,1,(target,tmp)->{
     *             return tmp.equals(target);
     *             });
     */
    public static <V> Boolean listContainObj(List<V> list, V v, BiFunction<V, V, Boolean> keyFunction) {
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(list)) {
            return Boolean.FALSE;
        }
        for (V tempV : list) {
            if (keyFunction.apply(tempV, v)) {
                return Boolean.TRUE;
            }
        }
        return Boolean.FALSE;
    }

    /**
     * list 转换为 数组 map的支持,使用了guava中的多维度HashBasedTable，如果存在多个相同的key，前面的会被后面的覆盖
     *
     * @param list
     * @param keyFunction
     * @param secondFunction
     * @param valFunction
     * @param <K1>
     * @param <K2>
     * @param <V>
     * @param <R>
     * @return
     */
    public static <K1, K2, V, R> HashBasedTable<K1, K2, R> listToHashBasedTable(List<V> list, Function<V, K1> keyFunction,
                                                                                Function<V, K2> secondFunction, Function<V, R> valFunction) {
        HashBasedTable<K1, K2, R> hashBasedTable = HashBasedTable.create();
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(list) || keyFunction == null || valFunction == null || secondFunction == null) {
            return hashBasedTable;
        }
        for (V v : list) {
            K1 key = keyFunction.apply(v);
            K2 secondKey = secondFunction.apply(v);
            R value = valFunction.apply(v);
            hashBasedTable.put(key, secondKey, value);
        }
        return hashBasedTable;
    }


    /**
     * 数组截取
     * example:
     * List<String> list = Lists.newArrayList("1","2","3","4","5","6","7","8","9","10");
     * List<String> subList = subList(list, 2, 5);
     * System.out.println(subList);//[2, 3, 4, 5]
     *
     * @return join result
     */
    public static <T> List<T> rangeToList(List<T> list, int start, int end) {
        if (CollectionUtils.isEmpty(list) || start < 1 || start > end) {
            return Lists.newArrayList();
        }
        List<T> newList = Lists.newArrayList();
        end = Math.min(end, list.size());
        for (int i = start-1; i < end; i++) {
            newList.add(list.get(i));
        }
        return newList;
    }
    /**
     * 数组截取
     * example:
     * List<String> list = Lists.newArrayList("1","2","3","4","5","6","7","8","9","10");
     * List<String> subList = subList(list, 2, 5);
     * System.out.println(subList);//[2, 3, 4, 5]
     *
     * @return join result
     */
    public static <T, R> List<R> rangeToList(List<T> list, int start, int end, Function<T, R> function) {
        if (CollectionUtils.isEmpty(list) || start < 1 || start > end) {
            return Lists.newArrayList();
        }
        List<R> newList = Lists.newArrayList();
        end = Math.min(end, list.size());
        for (int i = start-1; i < end; i++) {
            newList.add(function.apply(list.get(i)));
        }
        return newList;
    }

    /**
     * list 转为 另外一个list
     *
     * @param list
     * @param function
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> List<T> listToList(List<R> list, Function<R, T> function) {
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(list)) {
            return Lists.newArrayList();
        }
        List<T> newList = Lists.newArrayList();
        for (R r : list) {
            T t = function.apply(r);
            newList.add(t);
        }
        return newList;
    }

    /**
     * list 转 map 如果得到的key是相同的，可能会覆盖,
     *
     * @param list
     * @param function
     * @param <K>
     * @param <V>
     * @return example
     * *         List<String> list = new ArrayList<String>(){{
     * *             add("a");
     * *             add("b");
     * *             add("a");
     * *              }
     * *         };
     * * Map<String,String> listToMap = countList(list,obj->{
     * *     return obj;
     * * });
     */
    public static <K, V> Map<K, V> listToMap(List<V> list, Function<V, K> function) {
        Map<K, V> map = Maps.newHashMap();
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(list)) {
            return map;
        }
        for (V v : list) {
            K key = function.apply(v);
            map.put(key, v);
        }
        return map;
    }

    /**
     * list 转换为 map，如果得到的key是相同的，可能会覆盖
     *
     * @param list
     * @param keyFunction
     * @param valFunction
     * @param <K>
     * @param <V>
     * @param <R>
     * @return
     */
    public static <K, V, R> Map<K, R> listToMap(List<V> list, Function<V, K> keyFunction, Function<V, R> valFunction) {
        Map<K, R> map = Maps.newHashMap();
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(list) || keyFunction == null || valFunction == null) {
            return map;
        }
        for (V v : list) {
            K key = keyFunction.apply(v);
            R value = valFunction.apply(v);
            if (key == null || value == null) {
                continue;
            }
            map.put(key, value);
        }
        return map;
    }

    /**
     * list 转换为 数组 map的支持,使用了guava中的多维度HashBasedTable，如果存在多个相同的key，会存在队列中，不会被覆盖
     *
     * @param list           转换的list
     * @param keyFunction    生产第一个key的函数
     * @param secondFunction 生成第二个key的函数
     * @param valFunction    生成value的函数
     * @param supplier       如果为null 默认使用ArrayList作为存储队列，
     * @param <K1>
     * @param <K2>
     * @param <V>
     * @param <R>
     * @return
     */
    public static <K1, K2, V, R> HashBasedTable<K1, K2, Collection<R>> listToTableCollection(List<V> list, Function<V, K1> keyFunction,
                                                                                             Function<V, K2> secondFunction, Function<V, R> valFunction, Supplier<Collection<R>> supplier) {
        HashBasedTable<K1, K2, Collection<R>> hashBasedTable = HashBasedTable.create();
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(list) || keyFunction == null || valFunction == null || secondFunction == null) {
            return hashBasedTable;
        }
        for (V v : list) {
            K1 key = keyFunction.apply(v);
            K2 secondKey = secondFunction.apply(v);
            R value = valFunction.apply(v);
            Collection<R> rCollection = hashBasedTable.get(key, secondKey);
            if (rCollection == null) {
                if (supplier == null) {
                    rCollection = Lists.newArrayList();
                } else {
                    rCollection = supplier.get();
                }
            }
            rCollection.add(value);
            hashBasedTable.put(key, secondKey, rCollection);
        }
        return hashBasedTable;
    }

    /**
     * list 转为 另外一个list
     *
     * @return
     */
    @Deprecated
    public static <R> void listCopyToList(List<R> sourceList, List<R> targetList) {
        if (targetList == null) {
            return;
        }
        if (sourceList == null) {
            targetList = null;
        }
        if (sourceList.size() == 0) {
            targetList.clear();
        }
        for (R r : sourceList) {
            targetList.add(r);
        }
    }

    /**
     * list 转换为 map，如果得到的key是相同的，不会被覆盖，会存储到队列中
     *
     * @param list
     * @param keyFunction
     * @param valFunction
     * @param supplier    如果为null 默认使用ArrayList作为存储队列，
     * @param <K>
     * @param <V>
     * @param <R>
     * @return
     */
    public static <K, V, R> Map<K, Collection<R>> listToMapCollection(List<V> list, Function<V, K> keyFunction, Function<V, R> valFunction,
                                                                      Supplier<Collection<R>> supplier) {

        Map<K, Collection<R>> map = Maps.newHashMap();
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(list) || keyFunction == null || valFunction == null) {
            return map;
        }
        if (supplier == null) {
            throw new IllegalArgumentException("supplier is null");
        }
        for (V v : list) {
            K key = keyFunction.apply(v);
            Collection<R> rList = map.get(key);
            R value = valFunction.apply(v);
            if (rList == null) {

                rList = supplier.get();
                map.put(key, rList);
            }
            if (key == null || value == null) {
                continue;
            }
            rList.add(value);
        }
        return map;
    }

    /**
     * list 转换为 map，如果得到的key是相同的，不会被覆盖，会存储到队列中,结果使用ArrayList存储
     *
     * @param list
     * @param keyFunction
     * @param valFunction
     * @param <K>
     * @param <V>
     * @param <R>
     * @return
     */
    public static <K, V, R> Map<K, List<R>> listToMapList(List<V> list, Function<V, K> keyFunction, Function<V, R> valFunction) {
        Map<K, List<R>> map = Maps.newHashMap();
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(list) || keyFunction == null || valFunction == null) {
            return map;
        }
        for (V v : list) {
            K key = keyFunction.apply(v);
            List<R> rList = map.get(key);
            R value = valFunction.apply(v);
            if (rList == null) {
                rList = Lists.newArrayList();
                map.put(key, rList);
            }
            if (key == null || value == null) {
                continue;
            }
            rList.add(value);
        }
        return map;
    }

    /**
     * list 转换为 map，如果得到的key是相同的，不会被覆盖，会存储到队列中,
     *
     * @param list
     * @param map
     * @param keyFunction
     * @param valFunction
     * @param <K>
     * @param <V>
     * @param <R>
     * @return
     * @see #listToMapList
     */
    @Deprecated
    public static <K, V, R> Map<K, List<R>> listToMapList(List<V> list, Map<K, List<R>> map, Function<V, K> keyFunction,
                                                          Function<V, R> valFunction) {
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(list) || keyFunction == null || valFunction == null) {
            return map;
        }
        for (V v : list) {
            K key = keyFunction.apply(v);
            List<R> rList = map.get(key);
            R value = valFunction.apply(v);
            if (rList == null) {
                rList = Lists.newArrayList();
            }
            if (key == null || value == null) {
                continue;
            }
            rList.add(value);
            map.put(key, rList);
        }
        return map;
    }

    /**
     * 将数组分割，如果数组长度不够，则分割为一组
     * example:
     * List<String> list = Lists.newArrayList("1","2","3","4","5","6","7","8","9","10");
     * int size = 3;
     * List<List<String>> splitList = splitList(list, size, Function.identity());
     * System.out.println(splitList);
     * [
     * [1, 2, 3],
     * [4, 5, 6],
     * [7, 8, 9],
     * [10]
     * ]
     *
     * @param allList
     * @param subLength
     * @param <T>
     * @return
     */
    public static <T, R> List<List<R>> splitList(List<T> allList, int subLength, Function<T, R> function) {
        if (subLength < 0) {
            throw new IllegalArgumentException("subLengths is not right");
        }
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(allList)) {
            throw new IllegalArgumentException("allList is not right");
        }
        if (function == null) {
            throw new IllegalArgumentException("function is null");
        }
        List<List<R>> splitList = Lists.newArrayList();

        List<R> cloneList = null;
        int tick = 0;
        for (T temp : allList) {
            if (cloneList == null) {
                cloneList = Lists.newArrayList();
            }
            tick++;
            R r = function.apply(temp);
            cloneList.add(r);
            if (tick % subLength == 0) {
                splitList.add(cloneList);
                cloneList = null;
            }
        }
        if (!CollectionUtils.isEmpty(cloneList)) {
            splitList.add(cloneList);
        }
        return splitList;
    }
    /**
     * 将数组分割，如果数组长度不够，则分割为一组
     * example:
     * List<String> list = Lists.newArrayList("1","2","3","4","5","6","7","8","9","10");
     * int size = 3;
     * List<List<String>> splitList = splitList(list, size, Function.identity());
     * System.out.println(splitList);
     * [
     * [1, 2, 3],
     * [4, 5, 6],
     * [7, 8, 9],
     * [10]
     * ]
     *
     * @param allList
     * @param subLength
     * @param <T>
     * @return
     */
    public static <T> List<List<T>> splitList(List<T> allList, int subLength) {
        if (subLength < 0) {
            throw new IllegalArgumentException("subLengths is not right");
        }
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(allList)) {
            throw new IllegalArgumentException("allList is not right");
        }
        List<List<T>> splitList = Lists.newArrayList();

        List<T> cloneList = null;
        int tick = 0;
        for (T temp : allList) {
            if (cloneList == null) {
                cloneList = Lists.newArrayList();
            }
            tick++;

            cloneList.add(temp);
            if (tick % subLength == 0) {
                splitList.add(cloneList);
                cloneList = null;
            }
        }
        if (!org.apache.commons.collections4.CollectionUtils.isEmpty(cloneList)) {
            splitList.add(cloneList);
        }
        return splitList;
    }

    /**
     * map 转换为 map
     *
     * @param sourceMap
     * @param keyFunction
     * @param valFunction
     * @param <SK>
     * @param <SV>
     * @param <DK>
     * @param <DV>        Map<String,String> source = new HashMap<String,String>();
     *                    source.put("a","a");
     *                    source.put("b","b");
     *                    Map<String,String> result = mapToMap(source,(key,val)->{key+value},(key,val)->{key+value});
     * @return
     */
    public static <SK, SV, DK, DV> Map<DK, DV> mapToMap(Map<SK, SV> sourceMap, BiFunction<SK, SV, DK> keyFunction,
                                                        BiFunction<SK, SV, DV> valFunction) {
        if (MapUtils.isEmpty(sourceMap)) {
            return Maps.newHashMap();
        }
        if (keyFunction == null) {
            return Maps.newHashMap();
        }
        if (valFunction == null) {
            return Maps.newHashMap();
        }
        Map<DK, DV> destMap = Maps.newHashMap();

        sourceMap.forEach(((sk, sv) -> {
            DK dk = keyFunction.apply(sk, sv);

            DV dv = valFunction.apply(sk, sv);

            destMap.put(dk, dv);
        }));
        return destMap;
    }

    /**
     * 删除数组中重复的元素，同 removeDuplicateCase
     *
     * @param array
     * @param comparator
     * @param <T>
     * @return
     */
    public static <T> T[] removeDuplicate(T[] array, Comparator<T> comparator) {
        if (array.length == 0) {
            return array;
        }
        Arrays.sort(array, (o1, o2) -> comparator.compare(o1, o2));
        int slow = 0;
        int fast = 0;
        while (fast < array.length) {
            if (comparator.compare(array[slow], array[fast]) != 0) {
                slow++;
                array[slow] = array[fast];
            }
            fast++;
        }
        return Arrays.copyOfRange(array, 0, slow + 1);
    }
}
